package payserver

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/base64"
	"net/http"

	"google.golang.org/grpc/status"
)

var _ Crypto = (*RSA)(nil)
var _ Encrypt = (*RSAEncrypt)(nil)

type (
	RSA struct {
		privateKey *rsa.PrivateKey
	}

	RSAEncrypt struct {
		publicKey *rsa.PublicKey
	}

	RsaOption        func(*RSA)
	RSAEncryptOption func(*RSAEncrypt)
)

const (
	defaultPublicKey  = `MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtBjltYRRy4mB0egHLHDpVQPJ6dhvocbd4V20OxTRyCgCrYKGz71cw59lvzTClhez2Gh0JbbmSNSAeJpsrRBnjO7kLiL5kigsH8zMqsniD62cqeWVCccAAERmA52E++XTi5WTcUGwygY3JXjh+f3PF+o/+7iWxon5rUL75Mb0annuXJFQcKFiU/wv40HwkLWwSPgXXDpmYYVailsSJUjI0mgQGRJRFODCVVx5YOmFM6iH8DOmG8PGZ//WLjvNp3KA7U1ujyMiohBA/NGZsHbNGx2ctvP5SYwkqvhKUn0TPF2YthrHc0M3UHqp/el/XoVdUgsHpdX+CiV0ID3lTBZToQIDAQAB`
	defaultPrivateKey = `MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC0GOW1hFHLiYHR6AcscOlVA8np2G+hxt3hXbQ7FNHIKAKtgobPvVzDn2W/NMKWF7PYaHQltuZI1IB4mmytEGeM7uQuIvmSKCwfzMyqyeIPrZyp5ZUJxwAARGYDnYT75dOLlZNxQbDKBjcleOH5/c8X6j/7uJbGifmtQvvkxvRqee5ckVBwoWJT/C/jQfCQtbBI+BdcOmZhhVqKWxIlSMjSaBAZElEU4MJVXHlg6YUzqIfwM6Ybw8Zn/9YuO82ncoDtTW6PIyKiEED80Zmwds0bHZy28/lJjCSq+EpSfRM8XZi2GsdzQzdQeqn96X9ehV1SCwel1f4KJXQgPeVMFlOhAgMBAAECggEBAI49j8eiXzvjOd5AZNILx632lRWVdO2P9JRXfs6e7eUo/Jxvl+whQk/a5/BxSjJjPA7yyLE02IKzG1illqnFaBOeZieuRfDSu67OAOPvGRWK6E4jXmfffTe4zd2THoIZDdCT7WSpHmkhKZL1+3yHonXf9HLqYmMifEkEu5AANvCUUw9K8IlOmLGUXuH+an+tPNijY+tVpiW8CvT6SEra3NPkAfLvEH1bhDKz1Nx2JwTUIKDf8Dxt/oyvpnkex8Oupg6FmHuHlkhSiUdMMSDmcaTg4RzHZYL5U4Q2yULaF0ZtYxe5UDqWSQZSEpgwZ2KMNsSA8wKN0vslyo6HBtmZwAECgYEA4+3VjCw5M+ZCL/4JtgfrcKwVB3LFJlZkGKJenT0BXki1+okBlenjGdxmQX+GQDthj+6kOIZlOPjeYG/1yZFvMeDGnDtf6KcpB8jQoTzRluyaAb0BB2Jl2xrTsiEa23b5+/PYSci4OKalIaGkPkro4VoY8zFcYoOL4zwM4N5mRaECgYEAykcExISqzSiVdm4GMID3kb0VP9zoXc4yVPedHW9iAueVLoUEL7vN2WKuR1l2SJ6z9RF6X4peZPHA4yVLHuAJirMRjnNG5lE2oqTGmljuIokMqeZJchixSXESZsazaZ4G72miPzYEZD4MtB1dYwyy8lF0zhLZvI8ZD3zXSd/ZTgECgYEAtypXpA+d4IE3y02BDFGM+LyxIY0vtcFTKyDAm+d8hAI2i6EyLwEHya5+VkBe6JtPqdUDD5GhIomMWz9d65/+Fb0mnkJwrow2wtS0I/62B20XzjHO89o1NEB4wvsrlBYmijzJIXI16QCyTzaQwKZ+QyqeRkDylxBTiEanqsXOtkECgYAHXgzTZ42dCVRgSuOY0qmxujRS7iXcfM0igR5M2yizuGGbnyam4m099LUqThzbykP9shRF9JE5lgCThWE2D6zpS1phWNuFOgIGbH/7US/jPCCk84lLSZDzftXPvn78YtAX2j4ZlUsVp5jo2oTzPZwq7UKW2uLpVkDwanig7TFKAQKBgErxCvt5Fu0wrEpfblW4GC5g/ug6nre7lrMhyx4nYBo0kTd+2Zqa8jGAMQ5ERgXR+DmRIrVWPN0uIHa88GC3qUsH8vfO0nINKfiE2TMWgWJPafAHOQYfqd5Q7pzMvctTAt8fGvshpWq1KcGPDM51mn5HXFv+heWgzkrGlTL9Pr/Y`
)

func NewRSA(opts ...RsaOption) (Crypto, error) {
	privateKey, err := ParsePrivateKey(defaultPrivateKey)
	if err != nil {
		return nil, err
	}

	r := &RSA{
		privateKey: privateKey,
	}
	for _, opt := range opts {
		opt(r)
	}

	return r, nil
}

func NewRSAEncrypt(opts ...RSAEncryptOption) (Encrypt, error) {
	publicKey, err := ParsePublicKey(defaultPublicKey)
	if err != nil {
		return nil, err
	}

	r := &RSAEncrypt{
		publicKey: publicKey,
	}
	for _, opt := range opts {
		opt(r)
	}

	return r, nil
}

func WithPrivateKey(privateKey *rsa.PrivateKey) RsaOption {
	return func(r *RSA) {
		r.privateKey = privateKey
	}
}

func WithPublicKey(publicKey *rsa.PublicKey) RSAEncryptOption {
	return func(r *RSAEncrypt) {
		r.publicKey = publicKey
	}
}

// Encrypt 加密
func (r *RSA) Encrypt(data []byte) ([]byte, error) {
	publicKey := r.privateKey.PublicKey
	encryptedMessage, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, &publicKey, data, nil)
	if err != nil {
		return nil, err
	}
	return []byte(base64.StdEncoding.EncodeToString(encryptedMessage)), nil
}

// Decrypt 解密
func (r *RSA) Decrypt(data []byte) ([]byte, error) {
	message, err := base64.StdEncoding.DecodeString(string(data))
	if err != nil {
		return nil, err
	}
	decryptedMessage, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, r.privateKey, message, nil)
	if err != nil {
		return nil, err
	}
	return decryptedMessage, nil
}

func (r *RSAEncrypt) Encrypt(data []byte) ([]byte, error) {
	encryptedMessage, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, r.publicKey, data, nil)
	if err != nil {
		return nil, err
	}
	return []byte(base64.StdEncoding.EncodeToString(encryptedMessage)), nil
}

func ParsePrivateKey(privateKeyStr string) (*rsa.PrivateKey, error) {
	// 解码 Base64 编码的私钥数据
	decodedKey, err := base64.StdEncoding.DecodeString(privateKeyStr)
	if err != nil {
		return nil, err
	}
	pri, err := x509.ParsePKCS1PrivateKey(decodedKey)
	if err == nil {
		return pri, nil
	}
	pri2, err := x509.ParsePKCS8PrivateKey(decodedKey)
	if err != nil {
		return nil, err
	}
	privateKey, ok := pri2.(*rsa.PrivateKey)
	if !ok {
		return nil, status.Errorf(http.StatusInternalServerError, "解析私钥失败")
	}
	return privateKey, nil
}

func ParsePublicKey(publicKeyStr string) (*rsa.PublicKey, error) {
	// 解码 Base64 编码的公钥数据
	decodedKey, err := base64.StdEncoding.DecodeString(publicKeyStr)
	if err != nil {
		return nil, err
	}

	// 解析公钥数据
	pub, err := x509.ParsePKIXPublicKey(decodedKey)
	if err != nil {
		pub, err = x509.ParsePKCS1PublicKey(decodedKey)
		if err != nil {
			return nil, err
		}
	}
	publicKey, ok := pub.(*rsa.PublicKey)
	if !ok {
		return nil, status.Errorf(http.StatusInternalServerError, "解析公钥失败")
	}

	return publicKey, err
}
